/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package com.inspur.edp.metadata.rtcustomization.core;

import com.google.common.collect.Lists;
import com.inspur.edp.lcm.metadata.api.entity.*;
import com.inspur.edp.lcm.metadata.api.entity.uri.MetadataURI;
import com.inspur.edp.lcm.metadata.cache.MetadataDistCacheManager;
import com.inspur.edp.lcm.metadata.cache.RtCacheHandler;
import com.inspur.edp.lcm.metadata.common.MetadataDtoConverter;
import com.inspur.edp.lcm.metadata.common.configuration.ContentManagerHelper;
import com.inspur.edp.lcm.metadata.common.context.RuntimeContext;
import com.inspur.edp.lcm.metadata.spi.MetadataContentManager;
import com.inspur.edp.metadata.rtcustomization.api.AbstractCustomizedContent;
import com.inspur.edp.metadata.rtcustomization.api.CustomizationRtService;
import com.inspur.edp.metadata.rtcustomization.api.CustomizationService;
import com.inspur.edp.metadata.rtcustomization.api.entity.*;
import com.inspur.edp.metadata.rtcustomization.api.exception.ErrorCodes;
import com.inspur.edp.metadata.rtcustomization.api.exception.LcmMetadataException;
import com.inspur.edp.metadata.rtcustomization.common.EnvironmentContext;
import com.inspur.edp.metadata.rtcustomization.common.MetadataCustomizationUtils;
import com.inspur.edp.metadata.rtcustomization.core.async.UpdateMetadataCacheRunnable;
import com.inspur.edp.metadata.rtcustomization.core.exception.MetadataExceptionHandler;
import com.inspur.edp.metadata.rtcustomization.core.manager.RpcManager;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import io.iec.edp.caf.rpc.api.service.RpcClient;
import io.iec.edp.caf.rpc.api.support.Type;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;


/**
 * 此类是CustomizationService的实现类，其中包含具体处理逻辑组织，不包含具体持久化存储的处理
 *
 * @author zhaoleitr
 */
@Slf4j
public class CustomizationServiceImp extends AbstractMetadataService implements CustomizationService {
    private final String SU_LCM = "Lcm";

    public CustomizationRtService customizationRtService;

    public CustomizationServiceImp(CustomizationRtService customizationRtService) {
        this.customizationRtService = customizationRtService;
    }

    MetadataCustomizationUtils utils = new MetadataCustomizationUtils();

    @Override
    public GspMetadata getMetadataWithDimensions(String basicMetadataId, String basicMetadataCertId, String firstDimension, String secondDimension) {
        if (StringUtils.isEmpty(basicMetadataId)) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "basicMetadataId");
        }
        RpcClient client = SpringBeanUtils.getBean(RpcClient.class);
        LinkedHashMap<String, Object> params = new LinkedHashMap<>();
        params.put("basicMetadataId", basicMetadataId);
        params.put("basicMetadataCertId", basicMetadataCertId);
        params.put("firstDimension", firstDimension);
        params.put("secondDimension", secondDimension);
        MetadataDto response;
        try {
            response = client.invoke(MetadataDto.class, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getMetadataWithDimensions", "Lcm", params, null);
        } catch (Exception e) {
            throw new LcmMetadataException(e, ErrorCodes.ECP_METADATA_0002, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getMetadataWithDimensions");
        }
        return MetadataDtoConverter.asMetadata(response);
    }

    @Override
    public GspMetadata getMetadataWithRootMdIdAndDimensions(String rootMetadataId, String basicMetadataCertId, String firstDimension, String secondDimension) {
        if (StringUtils.isEmpty(rootMetadataId)) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "rootMetadataId");
        }
        RpcClient client = SpringBeanUtils.getBean(RpcClient.class);
        LinkedHashMap<String, Object> params = new LinkedHashMap<>();
        params.put("rootMetadataId", rootMetadataId);
        params.put("basicMetadataCertId", basicMetadataCertId);
        params.put("firstDimension", firstDimension);
        params.put("secondDimension", secondDimension);
        MetadataDto response;
        try {
            response = client.invoke(MetadataDto.class, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getMetadataWithRootMdIdAndDimensions", "Lcm", params, null);
        } catch (Exception e) {
            throw new LcmMetadataException(e, ErrorCodes.ECP_METADATA_0002, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getMetadataWithRootMdIdAndDimensions");
        }
        return MetadataDtoConverter.asMetadata(response);
    }

    @Override
    public boolean saveExtMetadataWithDimensions(DimensionExtendEntity dimExtEntity) {
        if (Objects.isNull(dimExtEntity)) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "元数据扩展信息实体");
        }
        RpcClient client = SpringBeanUtils.getBean(RpcClient.class);
        LinkedHashMap<String, Object> params = new LinkedHashMap<>();
        DimensionExtendEntityDto dimExtEntityDto = utils.buildDimensionExtendEntityDto(dimExtEntity);
        params.put("dimExtEntityDto", dimExtEntityDto);
        try {
            return client.invoke(boolean.class, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.saveExtMetadataWithDimensions", "Lcm", params, null);
        } catch (Exception e) {
            throw new LcmMetadataException(e, ErrorCodes.ECP_METADATA_0002, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.saveExtMetadataWithDimensions");
        }
    }

    @Override
    public void deleteGeneratedMetadata(String metadataId) {
        if (StringUtils.isEmpty(metadataId)) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "元数据id");
        }
        RpcClient client = SpringBeanUtils.getBean(RpcClient.class);
        LinkedHashMap<String, Object> params = new LinkedHashMap<>();
        params.put("metadataId", metadataId);
        try {
            client.invoke(String.class, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.deleteGeneratedMetadata", "Lcm", params, null);
        } catch (Exception e) {
            throw new LcmMetadataException(e, ErrorCodes.ECP_METADATA_0002, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.deleteGeneratedMetadata");
        }
    }

    @Override
    public void deleteExtMetadata(String metadataId, String certId) {
        if (StringUtils.isEmpty(metadataId)) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "元数据id");
        }
        RpcClient client = SpringBeanUtils.getBean(RpcClient.class);
        LinkedHashMap<String, Object> params = new LinkedHashMap<>();
        params.put("metadataId", metadataId);
        params.put("certId", certId);
        try {
            client.invoke(String.class, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.deleteExtMetadata", "Lcm", params, null);
        } catch (Exception e) {
            throw new LcmMetadataException(e, ErrorCodes.ECP_METADATA_0002, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.deleteExtMetadata");
        }
    }

    @Override
    public boolean isExistExtendObjectWithDims(String basicMetadataId, String basicMetadataCertId, String firstDimension, String secondDimension) {
        if (StringUtils.isEmpty(basicMetadataId)) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "基础元数据id");
        }
        RpcClient client = SpringBeanUtils.getBean(RpcClient.class);
        LinkedHashMap<String, Object> params = new LinkedHashMap<>();
        params.put("basicMetadataId", basicMetadataId);
        params.put("basicMetadataCertId", basicMetadataCertId);
        params.put("firstDimension", firstDimension);
        params.put("secondDimension", secondDimension);
        try {
            return client.invoke(boolean.class, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.isExistExtendObjectWithDims", "Lcm", params, null);
        } catch (Exception e) {
            throw new LcmMetadataException(e, ErrorCodes.ECP_METADATA_0002, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.isExistExtendObjectWithDims");
        }
    }

    @Override
    public List<Metadata4Ref> getAllCustomizedMetadataInfo() {
        RpcClient client = SpringBeanUtils.getBean(RpcClient.class);
        LinkedHashMap<String, Object> params = new LinkedHashMap<>();
        Type<List> type = new Type<>(List.class, Metadata4Ref.class);
        try {
            return client.invoke(type, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getAllCustomizedMetadataInfo", "Lcm", params, null);
        } catch (Exception e) {
            throw new LcmMetadataException(e, ErrorCodes.ECP_METADATA_0002, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getAllCustomizedMetadataInfo");
        }
    }

    /**
     * 获取所有生成的元数据信息，包括运行时新建的元数据
     */
    @Override
    public List<Metadata4Ref> getAllGeneratedMetadataInfo() {
        RpcClient client = SpringBeanUtils.getBean(RpcClient.class);
        LinkedHashMap<String, Object> params = new LinkedHashMap<>();
        Type<List> type = new Type<>(List.class, Metadata4Ref.class);
        try {
            return client.invoke(type, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getAllGeneratedMetadataInfo", "Lcm", params, null);
        } catch (Exception e) {
            throw new LcmMetadataException(e, ErrorCodes.ECP_METADATA_0002, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getAllGeneratedMetadataInfo");
        }
    }

    @Override
    public List<Metadata4Ref> getAllCustomizedMetadataInfo(List<String> metadataTypes) {
        String types = "";
        if (metadataTypes != null && metadataTypes.size() > 0) {
            for (String metadataType : metadataTypes) {
                types += metadataType + ",";
            }
            types = types.substring(0, types.length() - 1);
        }
        RpcClient client = SpringBeanUtils.getBean(RpcClient.class);
        LinkedHashMap<String, Object> params = new LinkedHashMap<>();
        params.put("metadataTypes", types);
        Type<List> type = new Type<>(List.class, Metadata4Ref.class);
        try {
            return client.invoke(type, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getAllCustomizedMetadataInfoWithTypes", "Lcm", params, null);
        } catch (Exception e) {
            throw new LcmMetadataException(e, ErrorCodes.ECP_METADATA_0002, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getAllCustomizedMetadataInfoWithTypes");
        }
    }

    @Override
    public List<Metadata4Ref> getAllGeneratedMdInfoWithTypes(List<String> metadataTypes) {
        String types = "";
        if (metadataTypes != null && metadataTypes.size() > 0) {
            for (String metadataType : metadataTypes) {
                types += metadataType + ",";
            }
            types = types.substring(0, types.length() - 1);
        }
        RpcClient client = SpringBeanUtils.getBean(RpcClient.class);
        LinkedHashMap<String, Object> params = new LinkedHashMap<>();
        params.put("metadataTypes", types);
        Type<List> type = new Type<>(List.class, Metadata4Ref.class);
        try {
            return client.invoke(type, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getAllGeneratedMdInfoWithTypes", "Lcm", params, null);
        } catch (Exception e) {
            throw new LcmMetadataException(e, ErrorCodes.ECP_METADATA_0002, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getAllGeneratedMdInfoWithTypes");
        }
    }

    @Override
    public List<DimensionExtendEntity> getMetadataInfoRecusively(String basicMetadataID, String basicMetadataCertId) {
        if (StringUtils.isEmpty(basicMetadataID)) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "基础元数据id");
        }
        RpcClient client = SpringBeanUtils.getBean(RpcClient.class);
        LinkedHashMap<String, Object> params = new LinkedHashMap<>();
        params.put("basicMetadataID", basicMetadataID);
        params.put("basicMetadataCertId", basicMetadataCertId);

        Type<List> type = new Type<>(List.class, DimensionExtendEntity.class);
        try {
            return client.invoke(type, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getMetadataInfoListRecusively", "Lcm", params, null);
        } catch (Exception e) {
            throw new LcmMetadataException(e, ErrorCodes.ECP_METADATA_0002, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getMetadataInfoListRecusively");
        }
    }

    @Override
    public boolean releaseMetadataToRt(String metadataId, String certId) {
        if (StringUtils.isEmpty(metadataId)) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "元数据id");
        }
        RpcClient client = SpringBeanUtils.getBean(RpcClient.class);
        LinkedHashMap<String, Object> params = new LinkedHashMap<>();
        params.put("metadataId", metadataId);
        params.put("certId", certId);
        try {
            return client.invoke(boolean.class, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.releaseMetadataToRt", "Lcm", params, null);
        } catch (Exception e) {
            throw new LcmMetadataException(e, ErrorCodes.ECP_METADATA_0002, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.releaseMetadataToRt");
        }
    }

    @Override
    public DimensionExtendRelation getDimExtRelationByExtMetadata(String metadataId, String certId) {
        if (StringUtils.isEmpty(metadataId)) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "元数据id");
        }
        RpcClient client = SpringBeanUtils.getBean(RpcClient.class);
        LinkedHashMap<String, Object> params = new LinkedHashMap<>();
        params.put("metadataId", metadataId);
        params.put("certId", certId);
        try {
            return client.invoke(DimensionExtendRelation.class, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getDimExtRelationByExtMetadata", "Lcm", params, null);
        } catch (Exception e) {
            throw new LcmMetadataException(e, ErrorCodes.ECP_METADATA_0002, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getDimExtRelationByExtMetadata");
        }
    }

    @Override
    public GspMetadata getBasicMetadataByExtMdId(String metadataId, String certId) {
        if (StringUtils.isEmpty(metadataId)) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "元数据id");
        }
        RpcClient client = SpringBeanUtils.getBean(RpcClient.class);
        LinkedHashMap<String, Object> params = new LinkedHashMap<>();
        params.put("metadataId", metadataId);
        params.put("certId", certId);
        // 根据扩展元数据id从获取根基础元数据id
        String basicMetadataId;
        try {
            basicMetadataId = client.invoke(String.class, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getBasicMetadataIdByExtMdId", "Lcm", params, null);
        } catch (Exception e) {
            throw new LcmMetadataException(e, ErrorCodes.ECP_METADATA_0002, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getBasicMetadataIdByExtMdId");
        }
        // 先从缓存中获取基础元数据
        if(StringUtils.hasText(basicMetadataId)){
            GspMetadata basicMetadata = getMetadataFromCache(basicMetadataId, true);
            if (basicMetadata != null){
                return basicMetadata;
            }
        }

        MetadataDto response;
        try {
            response = client.invoke(MetadataDto.class, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getBasicMetadataByExtMdId", "Lcm", params, null);
        } catch (Exception e) {
            throw new LcmMetadataException(e, ErrorCodes.ECP_METADATA_0002, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getBasicMetadataByExtMdId");
        }
        return MetadataDtoConverter.asMetadata(response);
    }

    @Override
    public Metadata4Ref getBasicPkgMetadataByExtMdId(String metadataId, String certId) {
        if (StringUtils.isEmpty(metadataId)) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "元数据id");
        }
        RpcClient client = SpringBeanUtils.getBean(RpcClient.class);
        LinkedHashMap<String, Object> params = new LinkedHashMap<>();
        params.put("metadataId", metadataId);
        params.put("certId", certId);
        try {
            return client.invoke(Metadata4Ref.class, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getBasicPkgMetadataByExtMdId", "Lcm", params, null);
        } catch (Exception e) {
            throw new LcmMetadataException(e, ErrorCodes.ECP_METADATA_0002, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getBasicPkgMetadataByExtMdId");
        }
    }

    @Override
    public GspMetadata getParentMdByExtMdId(String metadataId, String certId) {
        if (StringUtils.isEmpty(metadataId)) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "元数据id");
        }
        RpcClient client = SpringBeanUtils.getBean(RpcClient.class);
        LinkedHashMap<String, Object> params = new LinkedHashMap<>();
        params.put("metadataId", metadataId);
        params.put("certId", certId);
        MetadataDto response;
        try {
            response = client.invoke(MetadataDto.class, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getParentMdByExtMdId", "Lcm", params, null);
        } catch (Exception e) {
            throw new LcmMetadataException(e, ErrorCodes.ECP_METADATA_0002, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getParentMdByExtMdId");
        }
        return MetadataDtoConverter.asMetadata(response);
    }

    @Override
    public List<DimensionExtendEntity> getExtMdByBasicMdId(String metadataId, String certId) {
        if (StringUtils.isEmpty(metadataId)) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "元数据id");
        }
        RpcClient client = SpringBeanUtils.getBean(RpcClient.class);
        LinkedHashMap<String, Object> params = new LinkedHashMap<>();
        params.put("metadataId", metadataId);
        params.put("certId", certId);
        Type<List> type = new Type<>(List.class, DimensionExtendEntity.class);
        try {
            return client.invoke(type, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getExtMdByBasicMdId", "Lcm", params, null);
        } catch (Exception e) {
            throw new LcmMetadataException(e, ErrorCodes.ECP_METADATA_0002, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getExtMdByBasicMdId");
        }
    }

    @Override
    public AbstractCustomizedContent getChangeset(String metadataId, String certId, String version) {
        if (StringUtils.isEmpty(metadataId)) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "元数据id");
        }
        RpcClient client = SpringBeanUtils.getBean(RpcClient.class);
        LinkedHashMap<String, Object> params = new LinkedHashMap<>();
        params.put("metadataId", metadataId);
        params.put("certId", certId);
        params.put("version", version);
        GspMdChangeset response;
        try {
            response = client.invoke(GspMdChangeset.class, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getChangeset", "Lcm", params, null);
        } catch (Exception e) {
            throw new LcmMetadataException(e, ErrorCodes.ECP_METADATA_0002, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getChangeset");
        }
        return utils.buildAbstractCustomizdContet(response);
    }

    @Override
    public void save(GspMetadata metadata) {
        RpcClient client = SpringBeanUtils.getBean(RpcClient.class);
        LinkedHashMap<String, Object> params = new LinkedHashMap<>();
        params.put("metadata", MetadataDtoConverter.asDto(metadata));
        try {
            client.invoke(String.class, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.save", "Lcm", params, null);
        } catch (Exception e) {
            throw new LcmMetadataException(e, ErrorCodes.ECP_METADATA_0002, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.save");
        }
    }

    @Override
    public GspMetadata saveMetadata(GspMetadata metadata) {
        MetadataDto metadataDto= MetadataDtoConverter.asDto(metadata);
        RpcClient client = SpringBeanUtils.getBean(RpcClient.class);
        LinkedHashMap<String, Object> params = new LinkedHashMap<>();
        params.put("metadataDto", metadataDto);
        MetadataDto responseMetadataDto;
        try {
            responseMetadataDto = client.invoke(MetadataDto.class, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.saveMetadata", "Lcm", params, null);
        } catch (Exception e) {
            throw new LcmMetadataException(e, ErrorCodes.ECP_METADATA_0002, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.saveMetadata", metadata.getHeader().getId());
        }
        GspMetadata savedMetadata=MetadataDtoConverter.asMetadata(responseMetadataDto);
        String language = RuntimeContext.getLanguage();
        String metadataKey = RtCacheHandler.getMetadataCacheKey(savedMetadata.getHeader().getId(), language);
        MetadataDistCacheManager.put(metadataKey, savedMetadata, null);
        return metadata;
    }

    @Override
    public GspMetadata initMetadata(GspMetadata metadata) {
        if(metadata==null){
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "metadata");
        }
        if(metadata.getHeader()==null){
            metadata.setHeader(new MetadataHeader());
        }
        if(!StringUtils.hasLength(metadata.getHeader().getId())){
            metadata.getHeader().setId(UUID.randomUUID().toString());
        }
        MetadataContentManager manager = ContentManagerHelper.getInstance().getManager(metadata.getHeader().getType());
        if (manager != null) {
            manager.build(metadata);
        }
        return metadata;
    }

    @Override
    public void saveCheck(GspMetadata metadata) {
        if (Objects.isNull(metadata)) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "元数据id");
        }
        RpcClient client = SpringBeanUtils.getBean(RpcClient.class);
        LinkedHashMap<String, Object> params = new LinkedHashMap<>();
        params.put("metadata", MetadataDtoConverter.asDto(metadata));
        try {
            client.invoke(String.class, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.saveCheck", "Lcm", params, null);
        } catch (Exception e) {
            throw new LcmMetadataException(e, ErrorCodes.ECP_METADATA_0002, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.saveCheck");
        }
    }

    @Override
    public List<Metadata4Ref> getMetadataList(String metadataTypes) {
        RpcClient client = SpringBeanUtils.getBean(RpcClient.class);
        LinkedHashMap<String, Object> params = new LinkedHashMap<>();
        params.put("metadataTypes", metadataTypes);
        Type<List> type = new Type<>(List.class, Metadata4Ref.class);
        try {
            return client.invoke(type, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getMetadataInfoListWithTypes", "Lcm", params, null);
        } catch (Exception e) {
            throw new LcmMetadataException(e, ErrorCodes.ECP_METADATA_0002, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getMetadataInfoListWithTypes");
        }
    }

    @Override
    public List<Metadata4Ref> getMetadataList(String metadataTypes, Boolean isInterPretation) {
        List<Metadata4Ref> metadataList = getMetadataList(metadataTypes);
        if (metadataList == null) {
            return new ArrayList<>();
        }
        metadataList = metadataList.stream().filter(metadata4Ref -> {
            boolean interPretationFlag = metadata4Ref.getPackageHeader().getProcessMode() != null && metadata4Ref.getPackageHeader().getProcessMode().equals(ProcessMode.interpretation);
            if (isInterPretation) {
                return interPretationFlag;
            } else {
                return !interPretationFlag;
            }
        }).collect(Collectors.toList());
        return metadataList;
    }

    @Override
    public List<Metadata4Ref> getMetadataList(String metadataTypes, ProcessMode processMode) {
        List<Metadata4Ref> metadataList = getMetadataList(metadataTypes);
        if (metadataList == null) {
            return new ArrayList<>();
        }
        metadataList = metadataList.stream().filter(metadata4Ref -> {
            if (metadata4Ref.getPackageHeader().getProcessMode() != null) {
                return metadata4Ref.getPackageHeader().getProcessMode().equals(processMode);
            } else {
                return !processMode.equals(ProcessMode.interpretation);
            }
        }).collect(Collectors.toList());
        return metadataList;
    }

    @Override
    public List<Metadata4Ref> getMetadataList() {
        RpcClient client = SpringBeanUtils.getBean(RpcClient.class);
        LinkedHashMap<String, Object> params = new LinkedHashMap<>();
        Type<List> type = new Type<>(List.class, Metadata4Ref.class);
        try {
            return client.invoke(type, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getMetadataList", "Lcm", params, null);
        } catch (Exception e) {
            throw new LcmMetadataException(e, ErrorCodes.ECP_METADATA_0002, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getMetadataList");
        }
    }

    @Override
    public GspMetadata getMetadataBySemanticId(String nameSpace, String code, String typeCode) {
        RpcClient client = SpringBeanUtils.getBean(RpcClient.class);
        LinkedHashMap<String, Object> params = new LinkedHashMap<>();
        params.put("nameSpace", nameSpace);
        params.put("code", code);
        params.put("typeCode", typeCode);
        MetadataDto response;
        try {
            response = client.invoke(MetadataDto.class, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getMetadataBySemanticId", "Lcm", params, null);
        } catch (Exception e) {
            throw new LcmMetadataException(e, ErrorCodes.ECP_METADATA_0002, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getMetadataBySemanticId");
        }
        return MetadataDtoConverter.asMetadata(response);
    }

    @Override
    public boolean isMdDeletable(String metadataId, String certId) {
        if (StringUtils.isEmpty(metadataId)) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "元数据id");
        }
        RpcClient client = SpringBeanUtils.getBean(RpcClient.class);
        LinkedHashMap<String, Object> params = new LinkedHashMap<>();
        params.put("metadataId", metadataId);
        params.put("certId", certId);
        try {
            return client.invoke(boolean.class, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.isMdDeletable", "Lcm", params, null);
        } catch (Exception e) {
            throw new LcmMetadataException(e, ErrorCodes.ECP_METADATA_0002, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.isMdDeletable");
        }
    }

    @Override
    public void removeCacheByMetadataIds(List<String> metadataIds) {
        if (CollectionUtils.isEmpty(metadataIds)) {
            return;
        }
        RpcClient client = SpringBeanUtils.getBean(RpcClient.class);
        LinkedHashMap<String, Object> params = new LinkedHashMap<>();
        params.put("metadataIds", metadataIds);
        try {
            client.invoke(void.class, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.removeCacheByMetadataIds", "Lcm", params, null);
        } catch (Exception e) {
            throw new LcmMetadataException(e, ErrorCodes.ECP_METADATA_0002, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.removeCacheByMetadataIds");
        }
    }

    @Override
    public GspMetadata getDynamicMetadataWithRootMdIDAndDimensions(String rootMetadataId, String rootMetadataCertId,
                                                                   String firstDimensionValue, String secondDimensionValue) {
        if (StringUtils.isEmpty(rootMetadataId)) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "元数据id");
        }
        RpcClient client = SpringBeanUtils.getBean(RpcClient.class);
        LinkedHashMap<String, Object> params = new LinkedHashMap<>();
        params.put("rootMetadataId", rootMetadataId);
        params.put("rootMetadataCertId", rootMetadataCertId);
        params.put("firstDimensionValue", firstDimensionValue);
        params.put("secondDimensionValue", secondDimensionValue);
        MetadataDto response = null;
        try {
            response = client.invoke(MetadataDto.class, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getDynamicMetadataWithRootMdIDAndDimensions", SU_LCM, params, null);
        } catch (Exception e) {
            throw new LcmMetadataException(e, ErrorCodes.ECP_METADATA_0002, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getDynamicMetadataWithRootMdIDAndDimensions");
        }
        return MetadataDtoConverter.asMetadata(response);
    }

    @Override
    protected GspMetadata getMetadataFromCache(String metadataId, boolean isI18n) {
        // 如果缓存模式是调试模式，则不用缓存
        if (EnvironmentContext.cacheMode == CacheModeEnum.debug) {
            return null;
        }
        GspMetadata metadata = MetadataDistCacheManager.get(metadataId, isI18n);
        if (metadata != null && metadata.getContent() == null) {
            log.error("从缓存中获取的元数据不为空，但是元数据内容为空：" + metadataId);
            log.error("堆栈信息如下：" + Arrays.toString(Thread.currentThread().getStackTrace()));
            return null;
        }
        return metadata;
    }

    @Override
    public MetadataStringDto invokeRpc(RpcClient client, LinkedHashMap<String, Object> params) {
        try {
            return client.invoke(MetadataStringDto.class, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getMetadataStringDto", "Lcm", params, null);
        } catch (Exception e) {
            throw new LcmMetadataException(e, ErrorCodes.ECP_METADATA_0002, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getMetadataStringDto");
        }
    }

    @Override
    protected void asyncUpdateCache(GspMetadata metadata, boolean isI18n) {
        UpdateMetadataCacheRunnable updateMetadataCacheRunnable = new UpdateMetadataCacheRunnable(MetadataScopeEnum.CUSTOMIZING, isI18n, metadata);
        new Thread(updateMetadataCacheRunnable).start();
    }

    @Override
    public GspMetadata getGspMetadata(MetadataQueryParam metadataQueryParam) {
        // 参数校验
        if (Objects.isNull(metadataQueryParam) ||
                Objects.isNull(metadataQueryParam.getMetadataId()) ||
                Objects.isNull(metadataQueryParam.getMetadataScopeEnum())) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0004);
        }
        log.debug("CustomizationServiceImp.getGspMetadata MetadataQueryParam is: {}", metadataQueryParam);

        if (MetadataScopeEnum.CUSTOMIZING == metadataQueryParam.getMetadataScopeEnum()) {
            return getMetadata(metadataQueryParam.getMetadataId(), metadataQueryParam.getIsI18n());
        } else {
            return customizationRtService.getMetadata(metadataQueryParam.getMetadataId(), metadataQueryParam.getIsI18n());
        }
    }

    @Override
    public GspMetadata getGspMetadata(MetadataURIQueryParam metadataURIQueryParam) {
        if (Objects.isNull(metadataURIQueryParam)
                || Objects.isNull(metadataURIQueryParam.getMetadataURI())
                || Objects.isNull(metadataURIQueryParam.getMetadataScopeEnum())
                || Objects.isNull(metadataURIQueryParam.getMetadataURI().getId())) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0004);
        }
        GspMetadata gspMetadata = getGspMetadata(new MetadataQueryParam(metadataURIQueryParam.getMetadataURI().getId(), metadataURIQueryParam.getIsI18n(), metadataURIQueryParam.getMetadataScopeEnum()));
        if (gspMetadata == null) {
            MetadataExceptionHandler.handleMetadataNotFoundException(metadataURIQueryParam.getMetadataURI(), metadataURIQueryParam.getSourceURI());
        }
        return gspMetadata;
    }
    @Override
    public MetadataDto getMetadataDto(MetadataURIQueryParam metadataURIQueryParam) {
        return MetadataDtoConverter.asDto(getGspMetadata(metadataURIQueryParam));
    }

    @Override
    public List<Metadata4Ref> getMetadataList(Metadata4RefQueryParam metadata4RefQueryParam) {
        if (Objects.isNull(metadata4RefQueryParam) ||
                (Objects.isNull(metadata4RefQueryParam.getMetadataScopeEnum()) && Objects.isNull(metadata4RefQueryParam.getSourceTypeEnumList()))) {
            return new ArrayList<>();
        }
        // 构造实际查询数据类型集合
        List<SourceTypeEnum> sourceTypeEnumList = buildSourceTypeEnumData(metadata4RefQueryParam);
        RpcClient client = SpringBeanUtils.getBean(RpcClient.class);
        LinkedHashMap<String, Object> params = new LinkedHashMap<>();
        params.put("metadataTypes", metadata4RefQueryParam.getMetadataTypeList());
        params.put("sourceTypeEnumList", sourceTypeEnumList);
        Type<List> type = new Type<>(List.class, Metadata4Ref.class);
        List<Metadata4Ref> metadataList = null;
        try {
            metadataList = client.invoke(type, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getMetadata4Refs", "Lcm", params, null);
        } catch (Exception e) {
            throw new LcmMetadataException(e, ErrorCodes.ECP_METADATA_0002, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getMetadata4Refs");
        }
        if (metadataList == null) {
            return new ArrayList<>();
        }
        if (Objects.isNull(metadata4RefQueryParam.getProcessMode())) {
            return metadataList;
        }
        metadataList = metadataList.stream().filter(metadata4Ref -> {
            if (Objects.nonNull(metadata4Ref.getPackageHeader()) && metadata4Ref.getPackageHeader().getProcessMode() != null) {
                return metadata4Ref.getPackageHeader().getProcessMode().equals(metadata4RefQueryParam.getProcessMode());
            } else {
                return true;
            }
        }).collect(Collectors.toList());
        return metadataList;
    }

    @Override
    public Metadata4RefPageQueryResult getMetadataListByQueryParam(Metadata4RefPageQueryParam metadata4RefQueryParam) {
        if (Objects.isNull(metadata4RefQueryParam) ||
                (Objects.isNull(metadata4RefQueryParam.getMetadataScopeEnum()) && Objects.isNull(metadata4RefQueryParam.getSourceTypeEnumList()))) {
            return new Metadata4RefPageQueryResult();
        }
        // 构造实际查询数据类型集合
        List<SourceTypeEnum> sourceTypeEnumList = buildSourceTypeEnumData(metadata4RefQueryParam);
        metadata4RefQueryParam.setSourceTypeEnumList(sourceTypeEnumList);

        LinkedHashMap<String, Object> params = new LinkedHashMap<>();
        params.put("metadata4RefQueryParam", metadata4RefQueryParam);

        RpcClient client = SpringBeanUtils.getBean(RpcClient.class);
        Type<Metadata4RefPageQueryResult> type = new Type<>(Metadata4RefPageQueryResult.class);
        Metadata4RefPageQueryResult result = null;
        try {
            result = client.invoke(type, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getMetadata4RefsByQueryParam", "Lcm", params, null);
        } catch (Exception e) {
            throw new LcmMetadataException(e, ErrorCodes.ECP_METADATA_0002, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getMetadata4RefsByQueryParam");
        }
        if (result == null) {
            return new Metadata4RefPageQueryResult();
        }
        if (Objects.isNull(metadata4RefQueryParam.getProcessMode())) {
            return result;
        }
        List<Metadata4Ref> metadataList = result.getList();
        metadataList = metadataList.stream().filter(metadata4Ref -> {
            if (Objects.nonNull(metadata4Ref.getPackageHeader()) && metadata4Ref.getPackageHeader().getProcessMode() != null) {
                return metadata4Ref.getPackageHeader().getProcessMode().equals(metadata4RefQueryParam.getProcessMode());
            } else {
                return true;
            }
        }).collect(Collectors.toList());
        return result;
    }

    @Override
    public void updateExtRelation(DimensionExtendRelation extendRelation) {
        if (Objects.isNull(extendRelation)) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_CUSTOMIZATION_0009);
        }
        if (StringUtils.isEmpty(extendRelation.getExtMdId())) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_CUSTOMIZATION_0010);
        }
        RpcClient client = SpringBeanUtils.getBean(RpcClient.class);
        LinkedHashMap<String, Object> params = new LinkedHashMap<>();
        params.put("extendRelation", extendRelation);
        try {
            client.invoke(String.class, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.updateExtRelation", "Lcm", params, null);
        }catch (Exception e) {
            throw new LcmMetadataException(e, ErrorCodes.ECP_METADATA_0002, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.updateExtRelation");
        }
    }

    public MetadataURI getRefMetadataURI(String metadataId) {
        RpcManager<MetadataURI> rpcManager = new RpcManager<>(new Type<>(MetadataURI.class), "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getRefMetadataURI");
        rpcManager.getParams().put("metadataId", metadataId);
        try {
            return rpcManager.invoke();
        } catch (Exception e) {
            throw new LcmMetadataException(e, ErrorCodes.ECP_METADATA_0002, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getRefMetadataURI");
        }
    }

    /**
     * 构造实际需要查询的数据类型
     *
     * @param metadata4RefQueryParam
     * @return
     */
    private List<SourceTypeEnum> buildSourceTypeEnumData(Metadata4RefQueryParam metadata4RefQueryParam) {
        List<SourceTypeEnum> sourceTypeEnumList = new ArrayList<>();
        // 设计时数据类型
        List<SourceTypeEnum> dtSourceTypeEnumList = Lists.newArrayList(SourceTypeEnum.CUSTOMIZING, SourceTypeEnum.GENERATED, SourceTypeEnum.MDPKG);
        // 运行时数据类型
        List<SourceTypeEnum> rtSourceTypeEnumList = Lists.newArrayList(SourceTypeEnum.GENERATED, SourceTypeEnum.MDPKG, SourceTypeEnum.CUSTOMIZED, SourceTypeEnum.NOCODE);
        // MetadataScopeEnum: 标识查询设计时或运行时元数据, 设计时：CUSTOMIZING、MDPKG、GENERATED 运行时：CUSTOMIZED、NOCODE、MDPKG、GENERATED
        // SourceTypeEnum: 标识查询哪些范围的数据，在MetadataScopeEnum参数的基础上做白名单过滤
        if (!Objects.isNull(metadata4RefQueryParam.getMetadataScopeEnum()) && Objects.isNull(metadata4RefQueryParam.getSourceTypeEnumList())) {
            sourceTypeEnumList.addAll(metadata4RefQueryParam.getMetadataScopeEnum() == MetadataScopeEnum.CUSTOMIZING ? dtSourceTypeEnumList : rtSourceTypeEnumList);
        }
        if (Objects.isNull(metadata4RefQueryParam.getMetadataScopeEnum()) && !Objects.isNull(metadata4RefQueryParam.getSourceTypeEnumList())) {
            sourceTypeEnumList.addAll(metadata4RefQueryParam.getSourceTypeEnumList());
        }
        if (!Objects.isNull(metadata4RefQueryParam.getMetadataScopeEnum()) && !Objects.isNull(metadata4RefQueryParam.getSourceTypeEnumList())) {
            for (SourceTypeEnum sourceTypeEnum : metadata4RefQueryParam.getSourceTypeEnumList()) {
                if (metadata4RefQueryParam.getMetadataScopeEnum() == MetadataScopeEnum.CUSTOMIZING) {
                    if (dtSourceTypeEnumList.contains(sourceTypeEnum)) {
                        sourceTypeEnumList.add(sourceTypeEnum);
                    }
                } else {
                    if (rtSourceTypeEnumList.contains(sourceTypeEnum)) {
                        sourceTypeEnumList.add(sourceTypeEnum);
                    }
                }
            }
        }
        return sourceTypeEnumList;
    }
    @Override
    public Metadata4Ref getMetadata4RefById(String metadataId) {
        RpcClient client = SpringBeanUtils.getBean(RpcClient.class);
        LinkedHashMap<String, Object> params = new LinkedHashMap<>();
        params.put("metadataId", metadataId);
        Metadata4Ref metadata4Ref = null;
        try {
            metadata4Ref = client.invoke(Metadata4Ref.class, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getMetadata4RefById", "Lcm", params, null);
        } catch (Exception e) {
            throw new LcmMetadataException(e, ErrorCodes.ECP_METADATA_0002, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getMetadata4RefById");
        }
        return metadata4Ref;
    }

    @Override
    public GspMetadata buildResourceMetadata(GspMetadata metadata) {
        RpcClient client = SpringBeanUtils.getBean(RpcClient.class);
        LinkedHashMap<String, Object> params = new LinkedHashMap<>();
        params.put("metadata", MetadataDtoConverter.asDto(metadata));
        MetadataDto resourceMetadata = null;
        try {
            resourceMetadata = client.invoke(MetadataDto.class, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.buildResourceMetadata", "Lcm", params, null);
        } catch (Exception e) {
            throw new LcmMetadataException(e, ErrorCodes.ECP_METADATA_0002, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.buildResourceMetadata");
        }
        return MetadataDtoConverter.asMetadata(resourceMetadata);
    }

    @Override
    public List<DimensionExtendRelation> getDimExtRelationListByExtMetadataType(String metadataType) {
        RpcClient client = SpringBeanUtils.getBean(RpcClient.class);
        LinkedHashMap<String, Object> params = new LinkedHashMap<>();
        params.put("metadataType", metadataType);
        Type<List> type = new Type<>(List.class, DimensionExtendRelation.class);
        try {
             return client.invoke(type, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getDimExtRelationListByExtMetadataType", "Lcm", params, null);
        } catch (Exception e) {
            throw new LcmMetadataException(e, ErrorCodes.ECP_METADATA_0002, "com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService.getDimExtRelationListByExtMetadataType");
        }
    }
}
